using SmartCommunity.Models;
using Mapster;
using Microsoft.EntityFrameworkCore;

namespace SmartCommunity.WebApi.Services.System
{
    /// <summary>
    /// 服务类：操作日志
    /// </summary>
    public class LogService : BaseService<LogEntity>, ILogService
    {
        #region 构造函数
        protected readonly SCDBContext ctx;
        private readonly DbContextOptions<SCDBContext> ops;
        private readonly IHttpContextAccessor _httpContextAccessor;
        public LogService(SCDBContext ctx, IHttpContextAccessor httpContextAccessor, DbContextOptions<SCDBContext> ops)
        {
            _httpContextAccessor = httpContextAccessor;
            this.ctx = ctx;
            this.ops = ops;
        }
        #endregion

        #region 数据查询 
        /// <summary>
        /// 分页查询
        /// </summary>
        public async Task<PageResult<LogDto>> FindPagedList(LogQuery logQuery, Pager pager, LoginUser user)
        {
            var query = ctx.Logs.AsNoTracking().Where(logQuery.GetQueryExpression());
            var data = await FindPagedList(query, pager, o => o.OrderByDescending(t => t.CreatedTime));
            return data.Map(o => o.Adapt<LogDto>());
        }

        /// <summary>
        /// 根据操作日志ID查询
        /// </summary>
        public async Task<LogDto> FindLogById(long logId)
        {
            var entity = await FindById(logId);
            return entity.Adapt<LogDto>();
        }

        /// <summary>
        /// 根据ID查询实体类
        /// </summary>
        private async Task<LogEntity> FindById(long id)
        {
            return await ctx.Logs.SingleOrDefaultAsync(a => a.LogId == id)
                ?? throw new NotFoundException($"找不到指定的操作日志,Id:{id}");
        }
        #endregion

        #region 删除日志

        /// <summary>
        /// 根据ID删除操作日志
        /// </summary>
        public async Task DeleteByIds(IEnumerable<long> ids, LoginUser user)
        {
            await ctx.Logs.Where(a => ids.Contains(a.LogId)).ExecuteDeleteAsync();
            // 提交事务
            await ctx.SaveChangesAsync();
        }

        /// <summary>
        /// 根据查询条件清除日志
        /// </summary>
        public async Task ClearLogs(LogQuery query)
        {
            var exp = query.GetQueryExpression();
            await ctx.Logs.Where(exp).ExecuteDeleteAsync();
        }
        #endregion


        #region 实现接口保存日志
        public async Task SaveLog(OperateLog operateLog)
        {
            // 使用新的context实例，不能直接使用注入的ctx，不然业务抛出异常这里又savechanges导致异常无法回滚
            using var context = new SCDBContext(ops);
            {
                var log = operateLog.Adapt<LogEntity>(new TypeAdapterConfig().ForType<OperateLog, LogEntity>()
                       .Map(d => d.ClientIp, s => s.RequestClient!.ClientIp, s => s.RequestClient != null)
                       .Map(d => d.ClientOs, s => s.RequestClient!.ClientOs, s => s.RequestClient != null)
                       .Map(d => d.ClientBrowser, s => s.RequestClient!.ClientBrowser, s => s.RequestClient != null)
                       .Map(d => d.CreatedBy, s => s.OperateBy)
                       .Map(d => d.CreatedTime, s => s.OperateTime).Config
                    );
                context.Logs.Add(log);
                await context.SaveChangesAsync();
            }
        }

        public async Task SaveLog(OperateType operateType, string logTitle, string logDetail)
        {
            var log = new OperateLog(logTitle, operateType, logDetail);
            log.MergeContextParam(_httpContextAccessor.HttpContext);
            await SaveLog(log);
        }
        #endregion
    }
}
